package com.ygqh.baby.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ygqh.baby.ao.DataStatus;
import com.ygqh.baby.ao.QueryInfo;
import com.ygqh.baby.ao.ResultSet;
import com.ygqh.baby.constant.RedisConstant;
import com.ygqh.baby.mapper.ActionProductMapper;
import com.ygqh.baby.po.ActionProduct;
import com.ygqh.baby.po.ActionProductExample;
import com.ygqh.baby.po.ActionProductExample.Criteria;
import com.ygqh.baby.po.YgProduct;
import com.ygqh.baby.po.YgProductPack;
import com.ygqh.baby.redis.RedisDao;
import com.ygqh.baby.service.ActionProductService;
import com.ygqh.baby.service.YgProductPackService;
import com.ygqh.baby.service.YgProductService;
import com.ygqh.baby.utils.DateConvertUtils;
import com.ygqh.baby.utils.SerializeUtils;

@Service
public class ActionProductServiceImpl implements ActionProductService {

	@Autowired
	private ActionProductMapper actionProductMapper;
	@Autowired
	private YgProductPackService ygProductPackService;
	@Autowired
	private YgProductService ygProductService;
	@Autowired
	private RedisDao redisDao;

	@Override
	public List<ActionProduct> find(Long actionId) {
		ActionProductExample example = new ActionProductExample();
		Criteria criteria = example.createCriteria();
		criteria.andStatusEqualTo(DataStatus.Valid.name());
		if (actionId != null) {

			criteria.andActionIdEqualTo(actionId);
		}
		return actionProductMapper.selectByExample(example);
	}

	@Override
	public int findCount(Long actionId) {
		ActionProductExample example = new ActionProductExample();
		Criteria criteria = example.createCriteria();
		criteria.andStatusEqualTo(DataStatus.Valid.name());
		if (actionId != null) {

			criteria.andActionIdEqualTo(actionId);
		}
		return actionProductMapper.countByExample(example);
	}

	@Override
	public ActionProduct findById(Long id) {
		return actionProductMapper.selectByPrimaryKey(id);
	}

	@Override
	public ActionProduct findBySkuCode(String skuCode, Long actionId) {
		ActionProductExample example = new ActionProductExample();
		example.createCriteria().andSkuCodeEqualTo(skuCode).andActionIdEqualTo(actionId).andStatusEqualTo(DataStatus.Valid.name());
		List<ActionProduct> list = actionProductMapper.selectByExample(example);
		if (CollectionUtils.isNotEmpty(list)) {
			return list.get(0);
		}
		return null;
	}

	@Override
	public int save(ActionProduct actionProduct) {
		return actionProductMapper.insertSelective(actionProduct);
	}

	@Override
	public int update(ActionProduct actionProduct) {
		return actionProductMapper.updateByPrimaryKeySelective(actionProduct);
	}

	@Override
	public ResultSet<ActionProduct> search(QueryInfo queryInfo, Long actionId, String q) {
		List<ActionProduct> list = actionProductMapper.selectSuper(queryInfo, actionId, q);
		int count = actionProductMapper.countSuper(actionId, q);
		ResultSet<ActionProduct> resultSet = new ResultSet<ActionProduct>(count, list);
		return resultSet;
	}

	@Override
	public int deleteSoft(Long[] ids) {
		Assert.notEmpty(ids);
		ActionProductExample example = new ActionProductExample();
		example.createCriteria().andIdIn(Arrays.asList(ids));
		ActionProduct record = new ActionProduct();

		return actionProductMapper.updateByExampleSelective(record, example);
	}

	@Override
	public int deleteSoft(Long id) {
		return this.deleteSoft(new Long[] { id });
	}

	@Override
	public int saveOrUpdate(ActionProduct actionProduct) {
		int r = 0;
		if (actionProduct.getId() != null) {
			r = this.update(actionProduct);
		} else {
			r = this.save(actionProduct);
		}
		return r;
	}

	@Override
	public int addBatch(List<ActionProduct> productList) {
		if (CollectionUtils.isNotEmpty(productList)) {
			return actionProductMapper.addBatch(productList);
		}
		return 0;
	}

	@Override
	public List<ActionProduct> findBySkuCodeList(Long actionId, List<String> skuList) {
		ActionProductExample example = new ActionProductExample();
		example.createCriteria().andActionIdEqualTo(actionId).andSkuCodeIn(skuList).andStatusEqualTo(DataStatus.Valid.name());
		return actionProductMapper.selectByExample(example);
	}

	@Override
	public ActionProduct findByBarCode(Long actionId, String barCode) {
		ActionProductExample example = new ActionProductExample();
		example.createCriteria().andActionIdEqualTo(actionId).andStatusEqualTo(DataStatus.Valid.name()).andBarCodeEqualTo(barCode);
		List<ActionProduct> list = actionProductMapper.selectByExample(example);
		return CollectionUtils.isEmpty(list) ? null : list.get(0);
	}

	@Override
	public void saveActionPackToRedis(Long packId[], Date endDate) {
		List<YgProductPack> packList = new ArrayList<>();
		for (Long id : packId) {
			YgProductPack pack = ygProductPackService.findById(id);
			String[] productIds = pack.getProductIds().split(",");
			List<Long> list = Arrays.asList(productIds).stream().map(o -> Long.valueOf(o)).collect(Collectors.toList());
			List<YgProduct> findByIds = ygProductService.findByIds(list.toArray(new Long[list.size()]));
			List<String> productCodeList = findByIds.stream().map(o -> o.getProductCode()).collect(Collectors.toList());
			pack.setProductIds(String.join(",", productCodeList));
			packList.add(pack);
		}
		redisDao.set(RedisConstant.ACTION_PACK_PRODUCT.getBytes(), SerializeUtils.serialize(packList), DateConvertUtils.addDay(endDate, 1).getTime());
	}

	@SuppressWarnings("unchecked")
	private List<YgProductPack> findActionPackFromRedis() {
		byte[] bs = redisDao.get(RedisConstant.ACTION_PACK_PRODUCT.getBytes());
		if (bs != null && bs.length > 0) {
			return (List<YgProductPack>) SerializeUtils.deserialize(bs);
		}
		return new ArrayList<>();
	}

	@Override
	public BigDecimal getTotalPriceFromProductList(List<ActionProduct> productList) {
		processPack(productList);
		Map<Long, List<ActionProduct>> collect = productList.stream().collect(Collectors.groupingBy(ActionProduct::getPackId));
		BigDecimal zero = new BigDecimal("0.00");
		BigDecimal totalPrice = zero;
		for (Map.Entry<Long, List<ActionProduct>> entry : collect.entrySet()) {
			Long packId = entry.getKey();
			List<ActionProduct> list = entry.getValue();
			Long tAmount = 0L; // 当前分组商品总数
			BigDecimal tPrice = zero; // 当前分组商品总金额
			Long packAmount = 0L; // 任选包商品数
			BigDecimal packPrice = zero; // 任选包价格
			if (packId.compareTo(0L) > 0) {
				packAmount = list.get(0).getPackAmount();
				packPrice = list.get(0).getPackPrice();
				sortProductList(list); // 按商品价格降序
			}
			boolean flag = true;
			for (ActionProduct p : list) {
				Long productAmount = p.getProductAmount();
				tPrice = tPrice.add(p.getSalesPrice().multiply(BigDecimal.valueOf(productAmount)));
				tAmount += productAmount;
				if (flag && packAmount > 0 && tAmount.compareTo(packAmount) >= 0) { // 达到任选包要求
					BigDecimal multiply = p.getSalesPrice().multiply(BigDecimal.valueOf(tAmount - packAmount));
					BigDecimal add = packPrice.add(multiply);
					if (tPrice.compareTo(add) > 0) {
						tPrice = add;
					}
					flag = false;
				}
			}
			totalPrice = totalPrice.add(tPrice);
		}
		return totalPrice;
	}

	private void sortProductList(List<ActionProduct> list) {
		Collections.sort(list, new Comparator<ActionProduct>() {
			@Override
			public int compare(ActionProduct o1, ActionProduct o2) {
				return o2.getSalesPrice().compareTo(o1.getSalesPrice());
			}
		});
	}

	private void processPack(List<ActionProduct> productList) {
		Map<String, List<ActionProduct>> productMap = productList.stream().collect(Collectors.groupingBy(ActionProduct::getProductCode));
		List<YgProductPack> packList = findActionPackFromRedis();
		if (CollectionUtils.isEmpty(packList)) {
			return;
		}
		packList.stream().forEach(pack -> {
			processPack(pack, productMap);
		});
	}

	private void processPack(YgProductPack pack, Map<String, List<ActionProduct>> productMap) {
		String[] productCodes = pack.getProductIds().split(",");
		for (String productCode : productCodes) {
			if (productMap.containsKey(productCode)) {
				productMap.get(productCode).stream().forEach(p -> {
					p.setPackId(pack.getId());
					p.setPackAmount(pack.getProductAmount());
					p.setPackPrice(pack.getPackPrice());
				});
			}
		}
	}

	@Override
	public List<ActionProduct> getProductList(ActionProduct product, String skuInfos, Long actionId) {
		List<ActionProduct> productList = new ArrayList<>();
		List<ActionProduct> list = null;
		if (StringUtils.isNotBlank(skuInfos)) {
			list = JSON.parseObject(skuInfos, new TypeReference<List<ActionProduct>>() {
			});
		}
		if (CollectionUtils.isNotEmpty(list)) {
			Map<String, List<ActionProduct>> skuInfoMap = list.stream().collect(Collectors.groupingBy(ActionProduct::getSkuCode));
			List<String> skuCodeList = new ArrayList<>(skuInfoMap.keySet());
			List<ActionProduct> list2 = this.findBySkuCodeList(actionId, skuCodeList);
			list2.stream().forEach(p -> {
				String skuCode = p.getSkuCode();
				Long productAmount = 0L;
				if (skuInfoMap.containsKey(skuCode)) {
					productAmount += skuInfoMap.get(skuCode).get(0).getProductAmount();
				}
				if (product != null && product.getSkuCode().equals(skuCode)) {
					productAmount++;
				}
				p.setProductAmount(productAmount);
			});
			if (product != null && !skuCodeList.contains(product.getSkuCode())) {
				product.setProductAmount(1L);
				list2.add(product);
			}
			productList.addAll(list2);
		} else if (product != null) {
			product.setProductAmount(1L);
			productList.add(product);
		}
		return productList;
	}

}
